package com.kristin.thread.threadpool;


import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;

// 线程池创建

/**
 * 线程池的执行逻辑
 * 1. 提交任务
 * 2. 当核心线程数 < corePoolSize，创建一个线程并执行任务
 * 3. 当核心线程数 >= corePoolSize，将任务放入阻塞队列中
 * 4. 继续提交一个任务，但阻塞队列已经满了 且 corePoolSize < 当前线程数 < maximunPoolSize ，创建 一个非核心线程，来执行任务
 * 5. 继续提交一个任务，阻塞队列已经满了且 当前线程数 = maximunPoolSize，执行拒绝策略
 */
public class CreateTreadPool {

    private static ThreadPoolExecutor executorService;

    public static class MyThreadFactory implements ThreadFactory {

        private final AtomicInteger threadNumber = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            Thread t = new Thread(null, r, "线程" + threadNumber.getAndIncrement(),
                    0);
            return t;
        }
    }

    public static void printThreadPoolExecutor() {
        BlockingQueue queue = executorService.getQueue();
        int corePoolSize = executorService.getCorePoolSize();
        int maximumPoolSize = executorService.getMaximumPoolSize();
        int poolSize = executorService.getPoolSize();
        int activeCount = executorService.getActiveCount();
        int largestPoolSize = executorService.getLargestPoolSize();
        long completedTaskCount = executorService.getCompletedTaskCount();

        StringBuilder sb = new StringBuilder();
        sb.append("corePoolSize").append("-").append(corePoolSize).append("\t");
        sb.append("maximumPoolSize").append("-").append(maximumPoolSize).append("\t");
        sb.append("poolSize(线程数量)").append("-").append(poolSize).append("\t");
        sb.append("activeCount(正在执行任务的线程数量)").append("-").append(activeCount).append("\t");
        sb.append("largestPoolSize").append("-").append(largestPoolSize).append("\t");
        sb.append("completedTaskCount").append("-").append(completedTaskCount).append("\t");
        sb.append("blockingQueue").append("-").append(queue.size()).append("\t");
        System.out.println(sb.toString());
    }


    private static final int COUNT_BITS = Integer.SIZE - 3;
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;


    // 自己建立一个ThreadPoolExecutor
    private static class MyThreadPoolExecutor extends ThreadPoolExecutor {


        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        }

        @Override
        protected void beforeExecute(Thread t, Runnable r) {
            System.out.println(Thread.currentThread().getName() + "-----------before------------");
        }

        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            System.out.println(Thread.currentThread().getName() + "-----------after------------");
        }
    }


    public static void main(String[] args) throws InterruptedException {
//        createFixedThreadPool();// 创建固定数量的线程池
//        createSingleThreadPool(); // 创建单线程的线程池
//        createCacheThreadPool(); // 创建线程池

        BlockingQueue blockingQueue = new ArrayBlockingQueue(2);
//        BlockingQueue blockingQueue = new LinkedBlockingQueue();
//        BlockingQueue blockingQueue = new SynchronousQueue();
//        BlockingQueue blockingQueue = new PriorityBlockingQueue();

        executorService = new MyThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS, blockingQueue, new MyThreadFactory(), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println("rejected task " + r);
            }
        });
        executorService.allowCoreThreadTimeOut(true);
        new Thread(() -> {
            while(true){
                printThreadPoolExecutor();
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
        for (int i = 0; i < 20; i++) {
            int finalI = i;
            executorService.submit(() -> {
                System.out.println("执行" + Thread.currentThread().getName() + "任务-" + finalI);
            });
        }

//        executorService.shutdownNow();

    }

    private static void createCacheThreadPool() {
        ExecutorService service = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            int finalI = i;
            service.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(Thread.currentThread().getName() + "-----" + finalI);
                }
            });
        }
        service.shutdown();
    }

    private static void createSingleThreadPool() {
        ExecutorService service = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 100; i++) {
            int finalI = i;
            service.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "-----" + finalI);
                }
            });
        }
    }


    public static void createFixedThreadPool() throws InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 100; i++) {
            int finalI = i;
            service.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "-----" + finalI);
                }
            });
        }
    }


}
